#ifndef _STREAM_TYPE_H_
#define _STREAM_TYPE_H_

#include <string.h>

#ifdef __cplusplus
extern "C" {
#endif

#define ReadAndPrintOnly

enum {
    T_Print = 1,
    T_Read,
    T_Write
};

enum {
    TQ_SIGN = 1,
    TQ_UNSIGN = 2
};

enum {
    TQ_BIG = 1,
    TQ_LITTLE = 2
};

enum {
    LOG_Verbose = 1,
    LOG_Debug,
    LOG_Info,
    LOG_Warning,
    LOG_Error
};

typedef struct {
    void *oft;
    int len;
} OftLen;

typedef struct {
    int pos;
    int bit;
    int len; // Byte
    int size; // Bit
    unsigned char sign; // 默认TQ_UNSIGN
    unsigned char sort; // 默认TQ_LITTLE
    unsigned char *buf;
} InOutStreamType;

#define LABEL_VALUE_MAX_LEN 1024

#define CheckInput(val) if (val == NULL) { ThrowError(__LINE__); }

#define BitCheck(val, bit) (((val) & (1 << (bit))) != 0)
#define BitClear(val, bit) ((val) &= ~(1 << (bit)))

#ifdef ReadAndPrintOnly
#define PauseNumber(val, type) \
    do { \
        long long valTmp = ReadNumber(); \
        if (val != NULL) *(val) = valTmp; \
        if (type == T_Print) { \
            PrintNumber(valTmp, T_Print); \
        } \
    } while (0)
#define PauseDecimal(val, type) \
    do { \
        double valTmp = ReadDecimal(); \
        if (val != NULL) *(val) = valTmp; \
        if (type == T_Print) { \
            PrintDecimal(valTmp, T_Print); \
        } \
    } while (0)

#else // ifndef ReadAndPrintOnly
#define PauseNumber(val, type) \
    do { \
        if (type == T_Read) { \
            *(val) = ReadNumber(); \
        } else if (type == T_Write) { \
            WriteNumber(*(val)); \
        } else { \
            PrintNumber(*(val)), T_Print); \
        } \
    } while (0)
#define PauseDecimal(val, type) \
    do { \
        if (type == T_Read) { \
            *(val) = ReadDecimal(); \
        } else if (type == T_Write) { \
            WriteDecimal(*(val)); \
        } else { \
            PrintDecimal(*(val), T_Print); \
        } \
    } while (0)
#endif // ReadAndPrintOnly

#define PrintNumber(val, type) if (type == T_Print) PrintLabelValue(Number2Str(val), T_Print)
#define PrintDecimal(val, type) if (type == T_Print) PrintLabelValue(Decimal2Str(val), T_Print)
#define PrintByString(val, type) if (type == T_Print) PrintString((char*) (val), sizeof(*(val)))
#define PrintByBytes(val, type) if (type == T_Print) PrintBytes((unsigned char*) (val), sizeof(*(val)))
#define NoPrint(val, type) PrintLabelValue("(...)", type)

extern InOutStreamType *InOut;

long long ReadNumber();
void WriteNumber(long long val);
const char *Number2Str(long long val);
double ReadDecimal();
void WriteDecimal(double val);
const char *Decimal2Str(double val);

void PrintString(const char *str, int len);
void PrintBytes(const unsigned char *bytes, int len);
void PrintTimeDate(void *time, int type);

void SetPos(int pos);
void SetSize(int size);
void SetAlign(int align);
int SetSign(int sign);
int SetSort(int sort);
int Available(void);

void *GetPosBuf(int pos);
int GetMaxCount(int baseSize);
int GetBufferSize(void *buf);
void *ST_Alloc(int size);
void ST_FreeAll(void);

void ThrowError(int errCode);
void Log(int type, const char *format, ...);

void PrintLevelAdd(int type);
void PrintLevelSub(int type);
void PrintLabelKey(const char *key, int type);
void PrintLabelValue(const char *val, int type);
void PrintLabelEndKey(int type);

__declspec(dllexport) void PauseAll(void *buf, int type);

#ifdef __cplusplus
}
#endif

#endif // _STREAM_TYPE_H_
